package com.ly.crawl.impl;

import com.ly.crawl.Capturer;
import com.ly.crawl.util.Utils;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class ListDataCapturer implements Capturer<List<Map<String, Object>>> {
    private Map<String, String> nacs = new LinkedHashMap<>();

    public ListDataCapturer(String... nameAndCssSelects) {
        for (int i = 0; i < nameAndCssSelects.length; i += 2) {
            nacs.put(nameAndCssSelects[i], nameAndCssSelects[i + 1]);
        }
    }

    public ListDataCapturer(Map<String, String> nacs) {
        this.nacs.putAll(nacs);
    }

    @Override
    public List<Map<String, Object>> capture(String url, Document doc) {
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, List<Object>> data = new LinkedHashMap<>();
        String maxKey = null;
        int maxCount = 0;
        for (Map.Entry<String, String> nc : nacs.entrySet()) {
            List<Object> values;
            if (nc.getValue() == null || nc.getValue().trim().isEmpty()) {
                values = new ArrayList<>();
                values.add(null);
            } else if (nc.getValue().matches("url\\(.+\\)")) {
                values = new ArrayList<>();
                String regex = nc.getValue().replaceAll("url\\((.+)\\)", "$1");
                values.add(url.replaceAll(regex, "$1"));
            } else {
                values = captureData(doc, nc.getValue());
            }
            String name = nc.getKey();
            if (name.endsWith("*")) {
                if (values.isEmpty()) {
                    return null;
                } else {
                    name = name.substring(0, name.length() - 1);
                }
            }
            data.put(name, values);
            // System.out.printf("%s (%d) : %s\n", nc.getKey(), values.size(), values);
        }
        for (Map.Entry<String, List<Object>> nc : data.entrySet()) {
            List<Object> values = nc.getValue();
            if (maxCount > 1 && values.size() > 1 && values.size() != maxCount) {
                throw new RuntimeException("值数量不一致: " + nc.getValue());
            }
            if (values.size() > maxCount) {
                maxKey = nc.getKey();
                maxCount = values.size();
            }
        }

        for (int i = 0; i < data.get(maxKey).size(); i++) {
            Map<String, Object> map = new LinkedHashMap<>();
            for (Map.Entry<String, List<Object>> e : data.entrySet()) {
                Object value;
                if (e.getValue().size() < maxCount) {
                    value = e.getValue().get(e.getValue().size() - 1);
                } else {
                    value = e.getValue().get(i);
                }
                map.put(e.getKey(), value);
            }
            // url 是 html 代码, 不存 url
            if (!url.matches("\\s*<.+")) {
                map.put("url", url);
            }
            list.add(map);
        }
        return list;
    }

    private List<Object> captureData(Document doc, String cssSelecter) {
        List<Object> ret = new ArrayList<>();
        String[] items = cssSelecter.split("==>");
        if (Utils.isParentCssQuery(items[0])) {
            List<Element> elist = Utils.getParentList(doc, items[0]);
            for (Element e : elist) {
                ret.add(items.length == 1 ? getValue(e, null) : getValue(e, items[1]));
            }
        } else {
            Elements es = doc.select(items[0]);
            for (Element e : es) {
                ret.add(items.length == 1 ? getValue(e, null) : getValue(e, items[1]));
            }
        }
        return ret;
    }

    public String[] getColumns() {
        return this.nacs.keySet().toArray(new String[nacs.size()]);
    }
}
